package com.qyx.pmpucat.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.poi.excel.ExcelUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.qyx.pmpucat.common.exception.ClientException;
import com.qyx.pmpucat.common.exception.ServiceException;
import com.qyx.pmpucat.dto.*;
import com.qyx.pmpucat.entity.*;
import com.qyx.pmpucat.enums.QuestionnaireTypeEnum;
import com.qyx.pmpucat.mapper.*;
import com.qyx.pmpucat.service.UserAnswerService;
import com.qyx.pmpucat.service.UserService;
import com.qyx.pmpucat.util.EapSem;
import com.qyx.pmpucat.util.Grm;
import com.qyx.pmpucat.util.PersonalityDescriptionHelper;
import com.qyx.pmpucat.util.SelectNextItemMfi;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.math3.linear.Array2DRowRealMatrix;
import org.apache.commons.math3.linear.RealMatrix;
import org.apache.poi.xwpf.usermodel.*;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.text.DecimalFormat;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.function.Function;
import java.util.stream.Collectors;

import static com.qyx.pmpucat.entity.table.QuestionTableDef.QUESTION;
import static com.qyx.pmpucat.entity.table.QuestionnaireTableDef.QUESTIONNAIRE;
import static com.qyx.pmpucat.entity.table.UserAnswerDetailTableDef.USER_ANSWER_DETAIL;
import static com.qyx.pmpucat.entity.table.UserAnswerTableDef.USER_ANSWER;

/**
 * 用户答题服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = {@Lazy, @Autowired})
public class UserAnswerServiceImpl implements UserAnswerService {

    private static final double D = 1.0;
    private static final String QUESTION_CACHE_KEY_PREFIX = "questions:questionnaire:";
    private static final int CACHE_EXPIRE_MINUTES = 30;
    public static double seReturnNum = 0.387d;
    private final UserAnswerMapper userAnswerMapper;
    private final UserAnswerDetailMapper userAnswerDetailMapper;
    private final QuestionnaireMapper questionnaireMapper;
    private final QuestionMapper questionMapper;
    private final OptionCategoryMapper optionCategoryMapper;
    private final UserService userService;
    private final RedisTemplate<String, Object> redisTemplate;

    @Override
    public Question submitSingleAnswer(UserAnswerSingleSubmitDTO submitDTO) {
        // 获取当前用户ID
        Long userId = StpUtil.getLoginIdAsLong();
        Long questionnaireId = submitDTO.getQuestionnaireId();
        Long userAnswerId = submitDTO.getUserAnswerId();
        Long questionId = submitDTO.getQuestionId();
        Long optionId = submitDTO.getOptionId();
        Long userAnswerGroupId = submitDTO.getUserAnswerGroupId();
        if (userAnswerGroupId == null) {
            throw new ClientException("用户答题组为空！");
        }

        // 首次答题随机题目逻辑
        if (userAnswerId == null) {
            // 创建新的答题记录
            UserAnswer newUserAnswer = createNewUserAnswer(userId, questionnaireId, userAnswerGroupId);
            // 返回随机选择的第一道题目
            Question randomFirstQuestion = getRandomFirstQuestion(questionnaireId);
//            Question randomFirstQuestion = questionMapper.selectOneByQuery(QueryWrapper.create().where(QUESTION.SORT.eq(49)).where(QUESTION.QUESTIONNAIRE_ID.eq(questionnaireId)));
            randomFirstQuestion.setUserAnswerId(newUserAnswer.getId());
            return randomFirstQuestion;
        }

        // 检查问卷是否存在且已发布
        Questionnaire questionnaire = questionnaireMapper.selectOneById(questionnaireId);
        if (questionnaire == null || questionnaire.getStatus() != 1) {
            throw new ClientException("问卷不存在或未发布！");
        }

        // 验证用户答题记录
        UserAnswer userAnswer = userAnswerMapper.selectOneById(userAnswerId);
        if (userAnswer == null || !userId.equals(userAnswer.getUserId()) || !questionnaireId.equals(userAnswer.getQuestionnaireId())) {
            throw new ClientException("本次问卷答题记录验证失败！");
        }

        // 保存当前答题详情
        UserAnswerDetail detail = new UserAnswerDetail();
        detail.setUserAnswerId(userAnswerId);
        detail.setQuestionId(questionId);
        detail.setOptionId(optionId);
        detail.setCreateBy(userId);
        userAnswerDetailMapper.insert(detail);

        // 1. 预校验，如果已经达到精度，就不进行计算
        if (userAnswer.getSeNum() != null && userAnswer.getSeNum() < seReturnNum) {
            // 如果精度已达标,获取结果
            userAnswer.setStatus(1);
            userAnswerMapper.update(userAnswer);
            return null;
        }

        // 2. CAT算法计算下一题
        return getRResult(userId, userAnswer, detail);

    }

    @Override
    public UserAnswer getUserAnswerDetail(Long id) {
        // 检查答题记录是否存在
        UserAnswer userAnswer = userAnswerMapper.selectOneWithRelationsById(id);
        if (userAnswer == null) {
            throw new ClientException("答题记录不存在");
        }

        return userAnswer;
    }

    @Override
    public List<UserAnswerDetailResponseDTO> getUserAnswerDetailList(Long userAnswerId) {
        // 检查答题记录是否存在
        UserAnswer userAnswer = userAnswerMapper.selectOneById(userAnswerId);
        if (userAnswer == null) {
            throw new ClientException("答题记录不存在");
        }

        // 查询答题详情列表
        QueryWrapper detailWrapper = QueryWrapper.create();
        detailWrapper.where(USER_ANSWER_DETAIL.USER_ANSWER_ID.eq(userAnswerId));
        List<UserAnswerDetail> detailList = userAnswerDetailMapper.selectListByQuery(detailWrapper);

        // 如果没有答题详情，返回空列表
        if (CollectionUtils.isEmpty(detailList)) {
            return new ArrayList<>();
        }

        // 获取问题ID列表
        List<Long> questionIds = detailList.stream()
                .map(UserAnswerDetail::getQuestionId)
                .distinct()
                .collect(Collectors.toList());

        // 批量查询问题信息
        QueryWrapper questionWrapper = QueryWrapper.create();
        questionWrapper.where(QUESTION.ID.in(questionIds));
        List<Question> questions = questionMapper.selectListByQuery(questionWrapper);
        Map<Long, Question> questionMap = questions.stream()
                .collect(Collectors.toMap(Question::getId, question -> question));

        // 构建选项映射（从问题对象中获取选项）
        Map<Long, Question.QuestionOption> optionMap = new HashMap<>();
        Set<Long> optionCategoryIds = new HashSet<>();
        for (Question question : questions) {
            if (question.getOptions() != null) {
                for (Question.QuestionOption option : question.getOptions()) {
                    optionMap.put(option.getId(), option);
                }
                // 从问题中获取选项分类ID
                if (question.getOptionCategoryId() != null) {
                    optionCategoryIds.add(question.getOptionCategoryId());
                }
            }
        }

        // 批量查询OptionCategory信息
        Map<Long, String> optionCategoryContentMap = new HashMap<>();
        Map<Long, OptionCategory> optionCategoryMap = optionCategoryMapper.selectAll().stream().collect(Collectors.toMap(OptionCategory::getId, Function.identity()));
        if (!optionCategoryIds.isEmpty()) {
            for (Long categoryId : optionCategoryIds) {
                OptionCategory category = optionCategoryMapper.selectOneById(categoryId);
                if (category != null && category.getOptions() != null && !category.getOptions().isEmpty()) {
                    // 取第一个选项的标签作为内容
                    optionCategoryContentMap.put(category.getId(), category.getOptions().get(0).getLabel());
                }
            }
        }

        // 组装返回数据
        List<UserAnswerDetailResponseDTO> resultList = new ArrayList<>();
        for (UserAnswerDetail detail : detailList) {
            UserAnswerDetailResponseDTO dto = new UserAnswerDetailResponseDTO();
            BeanUtil.copyProperties(detail, dto);
            Question question = questionMap.get(detail.getQuestionId());
            dto.setQuestionTitle(question.getTitle());
            dto.setQuestionType(question.getType());
            dto.setQuestionSort(question.getSort());
            dto.setOptionId(detail.getOptionId());
            List<Question.QuestionOption> options = question.getOptions();
            dto.setOptionFactorValue(options.stream().filter(i -> i.getId().equals(detail.getOptionId())).findFirst().get().getBetaj());
            OptionCategory optionCategory = optionCategoryMap.get(question.getOptionCategoryId());
            String label = optionCategory.getOptions().stream().filter(i -> Long.valueOf(i.getId()).equals(detail.getOptionId())).findFirst().get().getLabel();
            dto.setOptionContent(label);
            resultList.add(dto);
        }

        return resultList;
    }

    /**
     * 批量获取用户答题详情列表
     * @param userAnswerIds 用户答题记录ID列表
     * @return Map<用户答题记录ID, 答题详情列表>
     */
    private Map<Long, List<UserAnswerDetailResponseDTO>> batchGetUserAnswerDetailList(List<Long> userAnswerIds) {
        if (CollectionUtils.isEmpty(userAnswerIds)) {
            return new HashMap<>();
        }

        // 批量查询所有答题详情
        QueryWrapper detailWrapper = QueryWrapper.create();
        detailWrapper.where(USER_ANSWER_DETAIL.USER_ANSWER_ID.in(userAnswerIds));
        List<UserAnswerDetail> allDetails = userAnswerDetailMapper.selectListByQuery(detailWrapper);

        if (CollectionUtils.isEmpty(allDetails)) {
            return new HashMap<>();
        }

        // 获取所有问题ID
        List<Long> questionIds = allDetails.stream()
                .map(UserAnswerDetail::getQuestionId)
                .distinct()
                .collect(Collectors.toList());

        // 批量查询问题信息
        QueryWrapper questionWrapper = QueryWrapper.create();
        questionWrapper.where(QUESTION.ID.in(questionIds));
        List<Question> questions = questionMapper.selectListByQuery(questionWrapper);
        Map<Long, Question> questionMap = questions.stream()
                .collect(Collectors.toMap(Question::getId, Function.identity()));

        // 获取选项分类ID
        Set<Long> optionCategoryIds = questions.stream()
                .filter(q -> q.getOptionCategoryId() != null)
                .map(Question::getOptionCategoryId)
                .collect(Collectors.toSet());

        // 批量查询OptionCategory信息
        Map<Long, OptionCategory> optionCategoryMap = optionCategoryMapper.selectAll().stream()
                .filter(category -> optionCategoryIds.contains(category.getId()))
                .collect(Collectors.toMap(OptionCategory::getId, Function.identity()));

        // 按用户答题记录ID分组并构建返回数据
        Map<Long, List<UserAnswerDetailResponseDTO>> resultMap = new HashMap<>();
        
        for (UserAnswerDetail detail : allDetails) {
            UserAnswerDetailResponseDTO dto = new UserAnswerDetailResponseDTO();
            BeanUtil.copyProperties(detail, dto);
            
            Question question = questionMap.get(detail.getQuestionId());
            if (question != null) {
                dto.setQuestionTitle(question.getTitle());
                dto.setQuestionType(question.getType());
                dto.setQuestionSort(question.getSort());
                dto.setOptionId(detail.getOptionId());
                
                // 设置选项因子值
                List<Question.QuestionOption> options = question.getOptions();
                if (options != null) {
                    options.stream()
                            .filter(i -> i.getId().equals(detail.getOptionId()))
                            .findFirst()
                            .ifPresent(option -> dto.setOptionFactorValue(option.getBetaj()));
                }
                
                // 设置选项内容
                OptionCategory optionCategory = optionCategoryMap.get(question.getOptionCategoryId());
                if (optionCategory != null && optionCategory.getOptions() != null) {
                    optionCategory.getOptions().stream()
                            .filter(i -> Long.valueOf(i.getId()).equals(detail.getOptionId()))
                            .findFirst()
                            .ifPresent(option -> dto.setOptionContent(option.getLabel()));
                }
            }
            
            // 按用户答题记录ID分组
            resultMap.computeIfAbsent(detail.getUserAnswerId(), k -> new ArrayList<>()).add(dto);
        }
        
        return resultMap;
    }

    @Override
    public Page<UserAnswerListResponseDTO> getUserAnswerPage(UserAnswerQueryDTO queryDTO) {
        // 构建查询条件
        QueryWrapper queryWrapper = QueryWrapper.create();

        // 问卷ID条件
        if (queryDTO.getQuestionnaireId() != null) {
            queryWrapper.and(USER_ANSWER.QUESTIONNAIRE_ID.eq(queryDTO.getQuestionnaireId()));
        }

        // 用户ID条件
        if (queryDTO.getUserId() != null) {
            queryWrapper.and(USER_ANSWER.USER_ID.eq(queryDTO.getUserId()));
        }

        // 状态条件
        if (queryDTO.getStatus() != null) {
            queryWrapper.and(USER_ANSWER.STATUS.eq(queryDTO.getStatus()));
        }

        // 按创建时间倒序排序
        queryWrapper.orderBy(USER_ANSWER.CREATE_TIME.desc());

        // 分页查询
        Page<UserAnswer> userAnswerPage = userAnswerMapper.paginate(
                queryDTO.getPageNum(), queryDTO.getPageSize(), queryWrapper);

        // 转换为DTO
        List<UserAnswerListResponseDTO> dtoList = new ArrayList<>();
        if (!CollectionUtils.isEmpty(userAnswerPage.getRecords())) {
            // 获取问卷ID列表
            List<Long> questionnaireIds = userAnswerPage.getRecords().stream()
                    .map(UserAnswer::getQuestionnaireId)
                    .distinct()
                    .collect(Collectors.toList());

            // 批量查询问卷信息
            QueryWrapper questionnaireWrapper = QueryWrapper.create();
            questionnaireWrapper.where(QUESTIONNAIRE.ID.in(questionnaireIds));
            List<Questionnaire> questionnaires = questionnaireMapper.selectListByQuery(questionnaireWrapper);
            Map<Long, String> questionnaireTitleMap = questionnaires.stream()
                    .collect(Collectors.toMap(Questionnaire::getId, Questionnaire::getTitle));

            // 获取用户ID列表
            List<Long> userIds = userAnswerPage.getRecords().stream()
                    .map(UserAnswer::getUserId)
                    .distinct()
                    .collect(Collectors.toList());

            // 批量查询用户信息
            Map<Long, String> usernameMap = new HashMap<>();
            for (Long uid : userIds) {
                User user = userService.getById(uid);
                if (user != null) {
                    usernameMap.put(uid, user.getUsername());
                }
            }

            // 组装数据
            for (UserAnswer userAnswer : userAnswerPage.getRecords()) {
                UserAnswerListResponseDTO dto = new UserAnswerListResponseDTO();
                BeanUtils.copyProperties(userAnswer, dto);

                // 设置问卷标题
                dto.setQuestionnaireTitle(questionnaireTitleMap.get(userAnswer.getQuestionnaireId()));

                // 设置用户名
                dto.setUsername(usernameMap.get(userAnswer.getUserId()));

                dtoList.add(dto);
            }
        }

        // 构建分页结果
        Page<UserAnswerListResponseDTO> result = new Page<>();
        result.setPageSize(userAnswerPage.getPageSize());
        result.setPageNumber(userAnswerPage.getPageNumber());
        result.setTotalPage(userAnswerPage.getTotalPage());
        result.setTotalRow(userAnswerPage.getTotalRow());
        result.setRecords(dtoList);

        return result;
    }

    @Override
    public UserAnswerResultDTO getLatestUserAnswer(Long userId, Long questionnaireId) {
        // 检查问卷是否存在
        Questionnaire questionnaire = questionnaireMapper.selectOneById(questionnaireId);
        if (questionnaire == null) {
            throw new ClientException("问卷不存在");
        }

        // 查询最新的答题记录
        QueryWrapper queryWrapper = QueryWrapper.create();
        queryWrapper.where(USER_ANSWER.USER_ID.eq(userId));
        queryWrapper.and(USER_ANSWER.QUESTIONNAIRE_ID.eq(questionnaireId));
        queryWrapper.orderBy(USER_ANSWER.CREATE_TIME.desc());
        queryWrapper.limit(1);
        UserAnswer userAnswer = userAnswerMapper.selectOneByQuery(queryWrapper);

        // 如果没有答题记录，返回null
        if (userAnswer == null) {
            return null;
        }

        // 组装返回结果
        UserAnswerResultDTO resultDTO = UserAnswerResultDTO.builder()
                .userAnswerId(userAnswer.getId())
                .questionnaireId(questionnaireId)
                .questionnaireTitle(questionnaire.getTitle())
                .status(userAnswer.getStatus())
                .build();

        return resultDTO;
    }


    /**
     * 创建新的用户答题记录
     */
    private UserAnswer createNewUserAnswer(Long userId, Long questionnaireId, Long userAnswerGroupId) {
        UserAnswer userAnswer = new UserAnswer();
        userAnswer.setUserId(userId);
        userAnswer.setQuestionnaireId(questionnaireId);
        userAnswer.setStatus(0); // 未完成
        userAnswer.setCreateBy(userId);
        userAnswer.setCreateUser(userService.getById(userId).getUsername());
        userAnswer.setUserAnswerGroupId(userAnswerGroupId);
        userAnswerMapper.insert(userAnswer);
        return userAnswer;
    }

    /**
     * 获取随机首题
     */
    private Question getRandomFirstQuestion(Long questionnaireId) {
        List<Question> questions = getQuestionsByQuestionnaireIdFromCache(questionnaireId);
        if (questions.isEmpty()) {
            throw new ServiceException("未查询到题目！");
        }
        // 随机选择第一道题目
        return questions.get(new Random().nextInt(questions.size()));
    }

    /**
     * 从缓存获取问卷题目列表，如果缓存不存在则查询数据库并缓存
     */
    @SuppressWarnings("unchecked")
    private List<Question> getQuestionsByQuestionnaireIdFromCache(Long questionnaireId) {
        String cacheKey = QUESTION_CACHE_KEY_PREFIX + questionnaireId;

        try {
            // 先从缓存获取
            Object cachedQuestions = redisTemplate.opsForValue().get(cacheKey);
            if (cachedQuestions != null) {
                log.debug("从缓存获取问卷[{}]的题目列表", questionnaireId);
                return (List<Question>) cachedQuestions;
            }

            // 缓存不存在，查询数据库
            log.info("缓存不存在，从数据库查询问卷[{}]的题目列表", questionnaireId);
            QueryWrapper questionWrapper = QueryWrapper.create()
                    .where(QUESTION.QUESTIONNAIRE_ID.eq(questionnaireId))
                    .orderBy(QUESTION.SORT.asc());
            List<Question> questions = questionMapper.selectListByQuery(questionWrapper);

            // 将结果缓存到Redis，设置30分钟过期时间
            redisTemplate.opsForValue().set(cacheKey, questions, CACHE_EXPIRE_MINUTES, TimeUnit.MINUTES);
            log.debug("已将问卷[{}]的题目列表缓存到Redis，过期时间{}分钟", questionnaireId, CACHE_EXPIRE_MINUTES);

            return questions;
        } catch (Exception e) {
            log.error("Redis操作异常，直接查询数据库。问卷ID: {}, 错误: {}", questionnaireId, e.getMessage());
            // Redis异常时，直接查询数据库
            QueryWrapper questionWrapper = QueryWrapper.create()
                    .where(QUESTION.QUESTIONNAIRE_ID.eq(questionnaireId))
                    .orderBy(QUESTION.SORT.asc());
            return questionMapper.selectListByQuery(questionWrapper);
        }
    }


    public Question getRResult(Long userId, UserAnswer userAnswer, UserAnswerDetail detail) {
        // 查询所有这个人做过的题目
        List<UserAnswerDetail> userAnswerDetails = userAnswerDetailMapper.selectListByQuery(
                QueryWrapper.create().where(USER_ANSWER_DETAIL.USER_ANSWER_ID.eq(userAnswer.getId())).where(USER_ANSWER_DETAIL.CREATE_BY.eq(userId)));

        // 查询所有已回答题目的ID列表
        List<Long> answeredQuestionIds = userAnswerDetails.stream()
                .map(UserAnswerDetail::getQuestionId)
                .distinct()
                .collect(Collectors.toList());

        // 批量查询已回答的题目信息
        List<Question> answeredQuestions = new ArrayList<>();
        if (!CollectionUtils.isEmpty(answeredQuestionIds)) {
            QueryWrapper questionWrapper = QueryWrapper.create();
            questionWrapper.where(QUESTION.ID.in(answeredQuestionIds)).orderBy(QUESTION.ID, true);
            answeredQuestions = questionMapper.selectListByQuery(questionWrapper);
        }

        // 查询所有题目（使用缓存）
        List<Question> allQuestions = getQuestionsByQuestionnaireIdFromCache(userAnswer.getQuestionnaireId());
        int maxOptionsSize = allQuestions.stream().max(Comparator.comparing(i -> i.getOptions().size())).get().getOptions().size();

        // 构建响应数组
        List<Integer> tbs = new ArrayList<>();
        answeredQuestions.forEach(question -> {
            userAnswerDetails.forEach(answer -> {
                if (answer.getQuestionId().equals(question.getId())) {
                    tbs.add((int) (answer.getOptionId() - 1));
                }
            });
        });


        UserAnswer calculatedResult;

        if (userAnswer.getReNum() == null || userAnswer.getSeNum() == null) {
            // 首次计算
            calculatedResult = rCode(tbs, answeredQuestions);
            userAnswer.setReNum(calculatedResult.getReNum());
            userAnswer.setSeNum(calculatedResult.getSeNum());
            detail.setReNum(calculatedResult.getReNum());
            detail.setSeNum(calculatedResult.getSeNum());
        } else {
            // 基于现有数据重新计算
            calculatedResult = rCode(tbs, answeredQuestions);
            userAnswer.setReNum(calculatedResult.getReNum());
            userAnswer.setSeNum(calculatedResult.getSeNum());
            detail.setReNum(calculatedResult.getReNum());
            detail.setSeNum(calculatedResult.getSeNum());
        }

        // 更新用户答题记录
        userAnswerMapper.update(userAnswer);
        userAnswerDetailMapper.update(detail);


        // 选择下一个题目
        if (userAnswer.getSeNum() >= seReturnNum) {
            // 将 unansweredQuestions 转换为 RealMatrix
            double[][] itemParamsArray = allQuestions.stream()
                    .map(qn -> {
                        List<Question.QuestionOption> options = qn.getOptions();
                        List<Double> result = new ArrayList<>();
                        result.add(qn.getAlphj());
                        //  过滤掉第一个选项
                        result.addAll(options.stream().filter(i -> !i.getSort().equals(1)).map(Question.QuestionOption::getBetaj).toList());
                        //TODO 获取问卷选项最大个数
                        if (result.size() != maxOptionsSize) {
                            // 用NaN填充到7个元素，表示没有意义的值
                            while (result.size() < maxOptionsSize) {
                                result.add(Double.NaN);
                            }
                        }
                        return result.stream()
                                .mapToDouble(Double::doubleValue)
                                .toArray();
                    })
                    .toArray(double[][]::new);
            RealMatrix itemBank = new Array2DRowRealMatrix(itemParamsArray);

            // 已作答的题目集合
            Set<Integer> out = answeredQuestions.stream()
                    .map(Question::getSort)
                    .collect(Collectors.toSet());

            // 随机选题参数
            int randomesque = 1;

            // 使用估计出的 theta 值选择下一个题目
            Map<String, Object> nextItem = SelectNextItemMfi.selectItemMFI(userAnswer.getReNum(), itemBank, out, randomesque, D);

            // 获取选中的题目ID
            Integer questionSort = (Integer) nextItem.get("item");
            Question question = questionMapper.selectOneByQuery(QueryWrapper.create().where(QUESTION.SORT.eq(questionSort)).where(QUESTION.QUESTIONNAIRE_ID.eq(userAnswer.getQuestionnaireId())));
            question.setUserAnswerId(userAnswer.getId());
            return question;
        }
        userAnswer.setStatus(1);
        userAnswerMapper.update(userAnswer);
        return null;
    }

    public UserAnswer rCode(List<Integer> tbs, List<Question> answeredQuestions) {
        UserAnswer result = new UserAnswer();

        // 将项目参数矩阵转换为二维数组
        double[][] itemParams = new double[answeredQuestions.size()][7]; // 保持7列格式
        for (int i = 0; i < answeredQuestions.size(); i++) {
            Question q = answeredQuestions.get(i);
            itemParams[i][0] = q.getAlphj(); // 区分度参数

            // 将选项的factorValue填充到参数数组中，跳过第一个选项（sort=1）
            List<Question.QuestionOption> options = q.getOptions();
            for (int j = 1; j < 7 && j < options.size(); j++) { // 从第二个选项开始(j=1)
                Question.QuestionOption option = options.get(j);
                if (option != null && option.getBetaj() != null) {
                    itemParams[i][j] = option.getBetaj(); // 注意这里是itemParams[i][j]，不是j+1
                } else {
                    itemParams[i][j] = 0.0; // 如果betaj为null，用0填充
                }
            }

            // 如果选项数量不足7个，用默认值填充剩余位置
            for (int j = options.size(); j < 7; j++) {
                itemParams[i][j] = 0.0;
            }
        }

        // 将响应数据转换为数组
        int[] responses = tbs.stream().mapToInt(Integer::intValue).toArray();

        // 计算能力参数 theta
        double theta = Grm.eapEstGRM(itemParams, responses, Grm.D);

        // 计算标准误 SEM
        double sem = EapSem.eapSem1(theta, itemParams, responses);

        // 设置结果
        result.setSeNum(sem);
        result.setReNum(theta);

        return result;
    }

    public String toResult(Long userId) {
        // 查询用户的评估结果  
        UserAnswer userAnswer = userAnswerMapper.selectOneByQuery(
                QueryWrapper.create().where(USER_ANSWER.CREATE_BY.eq(userId))
                        .orderBy(USER_ANSWER.ID, false));
        if (userAnswer == null || userAnswer.getReNum() == null) {
            return "未找到评估结果";
        }

        DecimalFormat df = new DecimalFormat("0.00");
        double reNum = userAnswer.getReNum();

        // 根据评估分数返回不同的结果说明
        if (reNum >= -1.0 && reNum < -0.5) {
            return "能力水平：较低 (分数: " + df.format(reNum) + ")";
        } else if (reNum >= -0.5 && reNum < 0.0) {
            return "能力水平：中等偏下 (分数: " + df.format(reNum) + ")";
        } else if (reNum >= 0.0 && reNum < 0.5) {
            return "能力水平：中等 (分数: " + df.format(reNum) + ")";
        } else if (reNum >= 0.5 && reNum < 1.0) {
            return "能力水平：中等偏上 (分数: " + df.format(reNum) + ")";
        } else if (reNum >= 1.0) {
            return "能力水平：较高 (分数: " + df.format(reNum) + ")";
        } else {
            return "能力水平：未知 (分数: " + df.format(reNum) + ")";
        }
    }

    /**
     * 获取下一个推荐题目
     */
    private Question getNextRecommendedQuestion(Long userId, Long questionnaireId) {
        // 查询用户已回答的题目
        List<UserAnswerDetail> userAnswerDetails = userAnswerDetailMapper.selectListByQuery(
                QueryWrapper.create().where(USER_ANSWER_DETAIL.CREATE_BY.eq(userId)));

        // 获取已回答题目的ID列表
        List<Long> answeredQuestionIds = userAnswerDetails.stream()
                .map(UserAnswerDetail::getQuestionId)
                .distinct()
                .collect(Collectors.toList());

        // 从缓存获取所有题目
        List<Question> allQuestions = getQuestionsByQuestionnaireIdFromCache(questionnaireId);

        // 过滤出未回答的题目
        List<Question> unansweredQuestions = allQuestions.stream()
                .filter(question -> !answeredQuestionIds.contains(question.getId()))
                .collect(Collectors.toList());

        if (unansweredQuestions.isEmpty()) {
            return null; // 所有题目都已回答完毕
        }

        // 如果还有未回答的题目，返回第一个
        // 这里可以根据CAT算法进一步优化选题逻辑
        return unansweredQuestions.get(0);
    }

    public String getEvaluationResult(Long userAnswerId) {
        UserAnswer userAnswer = userAnswerMapper.selectOneById(userAnswerId);
        Double reNum = userAnswer.getReNum();
        String result = "";
        if (reNum < -1) {
            result = "恭喜您！评估结果显示，您的手机使用习惯处于非常健康的水平，未表现出任何问题性使用的迹象。您能够清晰地区分数字世界与现实生活之间的界限，在享受科技便利的同时，有效避免了过度依赖或沉迷行为。您可能具备较强的自我管理能力，能够在学习、工作、人际交往和休闲活动中合理安排手机使用时间，不会因频繁查看消息或刷短视频而干扰重要任务的完成。这种良好的数字自律不仅有助于提升专注力与效率，也保护了您的睡眠质量、情绪稳定和现实人际关系。您展现出的是一种成熟、平衡的科技使用态度，这在当今高度数字化的社会中尤为珍贵。建议您继续保持当前的良好习惯，例如设定“无手机时段”、睡前远离屏幕、优先面对面交流等。同时，您可以成为身边人的积极榜样，分享您的健康使用策略。未来也可定期进行自我检视，预防潜在的使用滑坡，持续享受科技带来的便利而非负担。";
        } else if (reNum >= -1 && reNum <= 1) {
            result = "您的手机使用情况总体处于正常范围，尚未出现严重的问题性使用行为，这是一个积极的信号。您能够在大多数情况下控制使用时间，手机作为工具服务于您的沟通、信息获取和娱乐需求，而非主导您的生活节奏。然而，评估也提示您可能存在一些轻微的依赖倾向，例如偶尔无意识地刷手机、在专注任务时被通知干扰，或在社交场合中不自觉地查看设备。这些行为虽未造成显著负面影响，但长期积累可能削弱注意力、影响人际深度连接，甚至轻微干扰情绪调节。意识到这一点是迈向更健康数字生活的关键一步。建议您开始有意识地审视自己的使用模式，例如记录每日屏幕使用时间、识别“自动刷机”情境（如无聊、焦虑时）。尝试设定每日“数字断食”时段（如用餐时不看手机）、启用专注模式、培养替代活动（如阅读、运动、冥想）。通过微小但持续的调整，您将逐步建立更自主、更有质量的科技使用方式，进一步提升生活整体幸福感与掌控感。";
        } else {
            result = "根据评估结果，您的手机使用已显示出一定的问题性倾向，可能对日常生活、学习效率、情绪状态或人际关系产生了一定影响。您可能经常感到难以控制使用时间，即使在不需要的情况下也会频繁查看手机，甚至在工作、学习或与人交谈时分心。这种依赖可能源于对社交反馈的渴求、逃避现实压力，或单纯的习惯性行为。长此以往，可能导致注意力分散、睡眠质量下降、现实社交减少、焦虑或孤独感增加。意识到问题是改变的第一步，您已经迈出了重要的一环。建议您立即采取行动，制定具体的使用限制计划，例如：设定每日屏幕使用上限、关闭非必要通知、建立“手机禁区”（如卧室）、使用专注类APP（如番茄钟）。同时，积极寻找替代活动来填补“空闲时间”，如运动、兴趣爱好、面对面交流。若自我调节困难，建议寻求心理咨询师或数字健康教练的专业支持。通过系统性调整，您可以逐步恢复对数字生活的掌控，重建健康的生活节奏与心理平衡。";
        }

        return result;
    }


    @Override
    public List<UserAnswerGroupResultDTO> getUserAnswerGroupList(Long userId) {
        // 构建查询条件
        QueryWrapper queryWrapper = QueryWrapper.create();

        // 如果指定了用户ID，则只查询该用户的记录
        if (userId != null) {
            queryWrapper.where(USER_ANSWER.USER_ID.eq(userId));
        }

        // 只查询有分组ID的记录
        queryWrapper.where(USER_ANSWER.USER_ANSWER_GROUP_ID.isNotNull());

        // 按分组ID和创建时间排序
        queryWrapper.orderBy(USER_ANSWER.USER_ANSWER_GROUP_ID.desc(), USER_ANSWER.CREATE_TIME.asc());

        // 查询所有答题记录
        List<UserAnswer> userAnswers = userAnswerMapper.selectListByQuery(queryWrapper);

        if (CollectionUtils.isEmpty(userAnswers)) {
            return new ArrayList<>();
        }

        // 按分组ID分组
        Map<Long, List<UserAnswer>> groupMap = userAnswers.stream()
                .collect(Collectors.groupingBy(UserAnswer::getUserAnswerGroupId));

        // 获取所有问卷ID
        List<Long> questionnaireIds = userAnswers.stream()
                .map(UserAnswer::getQuestionnaireId)
                .distinct()
                .collect(Collectors.toList());

        // 批量查询问卷信息
        QueryWrapper questionnaireWrapper = QueryWrapper.create();
        questionnaireWrapper.where(QUESTIONNAIRE.ID.in(questionnaireIds));
        List<Questionnaire> questionnaires = questionnaireMapper.selectListByQuery(questionnaireWrapper);
        Map<Long, String> questionnaireTitleMap = questionnaires.stream()
                .collect(Collectors.toMap(Questionnaire::getId, Questionnaire::getTitle));


        // 批量查询用户信息

        Map<Long, User> userMap = userService.mapUserByUserIds(userAnswers.stream().map(UserAnswer::getUserId).collect(Collectors.toSet()));


        // 构建结果列表
        List<UserAnswerGroupResultDTO> resultList = new ArrayList<>();

        for (Map.Entry<Long, List<UserAnswer>> entry : groupMap.entrySet()) {
            Long groupId = entry.getKey();
            List<UserAnswer> groupAnswers = entry.getValue();
            groupAnswers.forEach(i -> {
                i.setQuestionnaireTitle(questionnaireTitleMap.get(i.getQuestionnaireId()));
            });

            // 计算组状态：有一个未完成就是未完成
            Integer groupStatus = groupAnswers.stream()
                    .anyMatch(answer -> answer.getStatus() == 0) ? 0 : 1;

            // 获取最旧的创建时间
            Optional<UserAnswer> oldestAnswer = groupAnswers.stream()
                    .min(Comparator.comparing(UserAnswer::getCreateTime));


            // 构建分组结果
            UserAnswerGroupResultDTO groupResult = UserAnswerGroupResultDTO.builder()
                    .userAnswerGroupId(groupId)
                    .userId(groupAnswers.get(0).getUserId())
                    .username(userMap.get(groupAnswers.get(0).getUserId()).getRealName())
                    .status(groupStatus)
                    .createTime(oldestAnswer.map(UserAnswer::getCreateTime).orElse(null))
                    .userAnswerList(groupAnswers)
                    .completedCount((int) groupAnswers.stream().filter(answer -> answer.getStatus() == 1).count())
                    .totalCount(groupAnswers.size())
                    .build();

            resultList.add(groupResult);
        }

        // 按创建时间倒序排序
        resultList.sort((a, b) -> b.getCreateTime().compareTo(a.getCreateTime()));

        return resultList;
    }

    @Override
    public List<EvaluationResultBatchDTO> listEvaluationResult(Long userAnswerGroupId) {
        if (userAnswerGroupId == null) {
            return Collections.emptyList();
        }

        List<UserAnswer> userAnswers = listUserAnswerByGroupId(userAnswerGroupId);
        if (CollectionUtils.isEmpty(userAnswers)) {
            return Collections.emptyList();
        }


        if (userAnswers.size() == 1) {
            return userAnswers.stream().map(i -> EvaluationResultBatchDTO.builder()
                    .result(getEvaluationResult(i.getId()))
                    .userAnswerId(i.getId())
                    .reNum(i.getReNum())
                    .build()).toList();
        } else {

            List<Long> questionnairedList = userAnswers.stream().map(UserAnswer::getQuestionnaireId).toList();
            List<Questionnaire> questionnaires = questionnaireMapper.selectListByQuery(QueryWrapper.create().where(QUESTIONNAIRE.ID.in(questionnairedList)));

            return userAnswers.stream().map(i -> {
                Optional<Questionnaire> first = questionnaires.stream().filter(j -> j.getId().equals(i.getQuestionnaireId())).findFirst();
                if (first.isPresent()) {
                    Questionnaire questionnaire = first.get();
                    Integer type = questionnaire.getType();
                    return EvaluationResultBatchDTO.builder()
                            .result(PersonalityDescriptionHelper.getDescription(QuestionnaireTypeEnum.getByType(type), i.getReNum()))
                            .userAnswerId(i.getId())
                            .reNum(i.getReNum())
                            .build();
                } else {
                    return null;
                }

            }).toList();
        }

    }

    @Override
    public ResponseEntity<byte[]> downLoadWordBatch(Long userAnswerGroupId, Long userId) {
        try {
            //获取用户基本信息
            User user = userService.getById(userId);
            //姓名
            String realName = user.getRealName();
            //年龄
            Integer age = user.getAge();
            //当前日期
            LocalDateTime now = LocalDateTime.now();
            String testDate = now.getYear() + "年" + now.getMonthValue() + "月" + now.getDayOfMonth() + "日";

            List<UserAnswer> userAnswers = listUserAnswerByGroupId(userAnswerGroupId);
            if (CollectionUtils.isEmpty(userAnswers)) {
                throw new ClientException("未找到答题记录");
            }

            List<Long> questionnairedList = userAnswers.stream().map(UserAnswer::getQuestionnaireId).toList();
            List<Questionnaire> questionnaires = questionnaireMapper.selectListByQuery(QueryWrapper.create().where(QUESTIONNAIRE.ID.in(questionnairedList)));

            //不同类型的问卷的结果
            Map<QuestionnaireTypeEnum, EvaluationResultBatchDTO> resultMap = new HashMap<>();
            for (UserAnswer userAnswer : userAnswers) {
                Optional<Questionnaire> first = questionnaires.stream().filter(j -> j.getId().equals(userAnswer.getQuestionnaireId())).findFirst();
                if (first.isPresent()) {
                    Questionnaire questionnaire = first.get();
                    Integer type = questionnaire.getType();
                    QuestionnaireTypeEnum typeEnum = QuestionnaireTypeEnum.getByType(type);
                    if (typeEnum != null) {
                        EvaluationResultBatchDTO dto = EvaluationResultBatchDTO.builder()
                                .result(PersonalityDescriptionHelper.getDescription(typeEnum, userAnswer.getReNum()))
                                .userAnswerId(userAnswer.getId())
                                .reNum(userAnswer.getReNum())
                                .build();
                        resultMap.put(typeEnum, dto);
                    }
                }
            }

            // 读取模板文件
            InputStream templateStream = getClass().getClassLoader().getResourceAsStream("大五人格测评报告模板.docx");
            if (templateStream == null) {
                throw new ServiceException("找不到模板文件");
            }

            XWPFDocument document = new XWPFDocument(templateStream);

            // 替换占位符
            replaceTextInDocument(document, "{{USER_NAME}}", realName != null ? realName : "");
            replaceTextInDocument(document, "{{USER_AGE}}", age != null ? age.toString() : "");
            replaceTextInDocument(document, "{{TEST_DATE}}", testDate);

            // 替换五大人格维度的得分和描述
            DecimalFormat df = new DecimalFormat("0.00");

            // 外倾性
            EvaluationResultBatchDTO extraversion = resultMap.get(QuestionnaireTypeEnum.EXTRAVERSION);
            if (extraversion != null) {
                replaceTextInDocument(document, "{{EXTRAVERSION_SCORE}}", df.format(extraversion.getReNum()));
                replaceTextInDocument(document, "{{EXTRAVERSION_DESC}}", extraversion.getResult());
            } else {
                replaceTextInDocument(document, "{{EXTRAVERSION_SCORE}}", "未测试");
                replaceTextInDocument(document, "{{EXTRAVERSION_DESC}}", "未完成该维度测试");
            }

            // 宜人性
            EvaluationResultBatchDTO agreeableness = resultMap.get(QuestionnaireTypeEnum.AGREEABLENESS);
            if (agreeableness != null) {
                replaceTextInDocument(document, "{{AGREEABLENESS_SCORE}}", df.format(agreeableness.getReNum()));
                replaceTextInDocument(document, "{{AGREEABLENESS_DESC}}", agreeableness.getResult());
            } else {
                replaceTextInDocument(document, "{{AGREEABLENESS_SCORE}}", "未测试");
                replaceTextInDocument(document, "{{AGREEABLENESS_DESC}}", "未完成该维度测试");
            }

            // 尽责性
            EvaluationResultBatchDTO conscientiousness = resultMap.get(QuestionnaireTypeEnum.CONSCIENTIOUSNESS);
            if (conscientiousness != null) {
                replaceTextInDocument(document, "{{CONSCIENTIOUSNESS_SCORE}}", df.format(conscientiousness.getReNum()));
                replaceTextInDocument(document, "{{CONSCIENTIOUSNESS_DESC}}", conscientiousness.getResult());
            } else {
                replaceTextInDocument(document, "{{CONSCIENTIOUSNESS_SCORE}}", "未测试");
                replaceTextInDocument(document, "{{CONSCIENTIOUSNESS_DESC}}", "未完成该维度测试");
            }

            // 神经质
            EvaluationResultBatchDTO neuroticism = resultMap.get(QuestionnaireTypeEnum.NEUROTICISM);
            if (neuroticism != null) {
                replaceTextInDocument(document, "{{NEUROTICISM_SCORE}}", df.format(neuroticism.getReNum()));
                replaceTextInDocument(document, "{{NEUROTICISM_DESC}}", neuroticism.getResult());
            } else {
                replaceTextInDocument(document, "{{NEUROTICISM_SCORE}}", "未测试");
                replaceTextInDocument(document, "{{NEUROTICISM_DESC}}", "未完成该维度测试");
            }

            // 开放性
            EvaluationResultBatchDTO openness = resultMap.get(QuestionnaireTypeEnum.OPENNESS);
            if (openness != null) {
                replaceTextInDocument(document, "{{OPENNESS_SCORE}}", df.format(openness.getReNum()));
                replaceTextInDocument(document, "{{OPENNESS_DESC}}", openness.getResult());
            } else {
                replaceTextInDocument(document, "{{OPENNESS_SCORE}}", "未测试");
                replaceTextInDocument(document, "{{OPENNESS_DESC}}", "未完成该维度测试");
            }

            // 将文档写入字节数组
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            document.write(byteArrayOutputStream);
            document.close();
            templateStream.close();

            byte[] bytes = byteArrayOutputStream.toByteArray();
            String fileName = realName + "_大五人格测评报告_" + System.currentTimeMillis() + ".docx";

            return buildDownloadResponse(bytes, fileName);

        } catch (Exception e) {
            log.error("生成Word报告失败", e);
            throw new ServiceException("生成Word报告失败：" + e.getMessage());
        }
    }

    @Override
    public ResponseEntity<byte[]> downLoadWord(Long userAnswerGroupId, Long userId) {

        //获取用户基本信息
        User user = userService.getById(userId);
        //姓名
        String realName = user.getRealName();
        //年龄
        Integer age = user.getAge();
        //当前日期
        LocalDateTime now = LocalDateTime.now();
        String testDate = now.getYear() + "年" + now.getMonthValue() + "月" + now.getDayOfMonth() + "日";

        List<UserAnswer> userAnswers = listUserAnswerByGroupId(userAnswerGroupId);
        if (CollUtil.isEmpty(userAnswers) || userAnswers.size() != 1) {
            throw new ClientException("答题记录异常！");
        }
        UserAnswer userAnswer = userAnswers.get(0);
        String result = getEvaluationResult(userAnswer.getId());

        // 读取模板文件
        InputStream templateStream = getClass().getClassLoader().getResourceAsStream("问题性手机使用报告模板.docx");
        if (templateStream == null) {
            throw new ServiceException("找不到模板文件");
        }

        XWPFDocument document = null;
        try {
            document = new XWPFDocument(templateStream);

            DecimalFormat df = new DecimalFormat("0.00");
            // 替换占位符
            replaceTextInDocument(document, "{{USER_NAME}}", realName != null ? realName : "");
            replaceTextInDocument(document, "{{USER_AGE}}", age != null ? age.toString() : "");
            replaceTextInDocument(document, "{{TEST_DATE}}", testDate);
            replaceTextInDocument(document, "{{SCORE}}", df.format(userAnswer.getReNum()));
            replaceTextInDocument(document, "{{RESULT}}", result);

            // 将文档写入字节数组
            ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
            document.write(byteArrayOutputStream);
            document.close();
            templateStream.close();

            byte[] bytes = byteArrayOutputStream.toByteArray();
            String fileName = realName + "_问题性手机使用报告_" + System.currentTimeMillis() + ".docx";
            return buildDownloadResponse(bytes, fileName);
        } catch (IOException e) {
            throw new ServiceException("生成报告失败！");
        }
    }

    @Override
    public ResponseEntity<byte[]> exportUserAnswer(LocalDate startTime, LocalDate endTime) {
        try {
            // 1. 查询指定时间范围内的所有用户答题记录
            QueryWrapper queryWrapper = QueryWrapper.create();
            if (startTime != null && endTime != null) {
                queryWrapper.where(USER_ANSWER.CREATE_TIME.between(startTime, endTime.plusDays(1)));
            } else if (startTime != null) {
                queryWrapper.where(USER_ANSWER.CREATE_TIME.ge(startTime));
            } else if (endTime != null) {
                queryWrapper.where(USER_ANSWER.CREATE_TIME.le(endTime.plusDays(1)));
            }
            queryWrapper.where(USER_ANSWER.STATUS.eq(1)); // 只导出已完成的答题记录
            List<UserAnswer> allUserAnswers = userAnswerMapper.selectListByQuery(queryWrapper);

            if (CollectionUtils.isEmpty(allUserAnswers)) {
                // 返回空文件
                return buildDownloadResponse(new byte[0], "用户答题记录_" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE) + ".xlsx");
            }
            // 获取问卷信息
            List<Questionnaire> allQuestionnaires = questionnaireMapper.selectAll();
            Map<Long, Integer> questionnaireTypeMap = allQuestionnaires.stream().collect(Collectors.toMap(Questionnaire::getId, Questionnaire::getType));

            // 2. 按用户ID和问卷ID分组，找出每个用户对于不同questionnaireId的最新答题记录
            Map<String, UserAnswer> latestUserAnswers = new HashMap<>();
            for (UserAnswer userAnswer : allUserAnswers) {
                String key = userAnswer.getUserId() + "_" + userAnswer.getQuestionnaireId();
                UserAnswer existing = latestUserAnswers.get(key);
                if (existing == null || userAnswer.getCreateTime().after(existing.getCreateTime())) {
                    latestUserAnswers.put(key, userAnswer);
                }
            }

            // 3. 获取用户信息
            Set<Long> userIds = latestUserAnswers.values().stream()
                    .map(UserAnswer::getUserId)
                    .collect(Collectors.toSet());
            Map<Long, User> userMap = userService.mapUserByUserIds(userIds);

            // 4. 按用户ID分组，每个用户一条记录，包含多个问卷答题记录
            Map<Long, List<UserAnswer>> userAnswersByUserId = latestUserAnswers.values().stream()
                    .collect(Collectors.groupingBy(UserAnswer::getUserId));

            // 批量查询所有用户答题详情
            List<Long> allUserAnswerIds = latestUserAnswers.values().stream()
                    .map(UserAnswer::getId)
                    .collect(Collectors.toList());
            Map<Long, List<UserAnswerDetailResponseDTO>> userAnswerDetailsMap = batchGetUserAnswerDetailList(allUserAnswerIds);

            List<ExportUserAnswerDTO> exportData = new ArrayList<>();

            for (Map.Entry<Long, List<UserAnswer>> entry : userAnswersByUserId.entrySet()) {
                Long userId = entry.getKey();
                List<UserAnswer> userAnswers = entry.getValue();
                User user = userMap.get(userId);

                if (user == null) {
                    continue;
                }

                // 按问卷类型分组处理
                StringBuilder catAnswerData = new StringBuilder();
                StringBuilder questionnaireAnswerData = new StringBuilder();
                int totalQuestionCount = 0;
                Double finalReNum = null;
                Double finalSeNum = null;

                // 处理CAT问卷
                for (UserAnswer userAnswer : userAnswers) {
                    List<UserAnswerDetailResponseDTO> answerDetails = userAnswerDetailsMap.get(userAnswer.getId());
                    if (answerDetails == null || answerDetails.isEmpty()) {
                        continue;
                    }
                    
                    if (QuestionnaireTypeEnum.CAT.getType().equals(questionnaireTypeMap.get(userAnswer.getQuestionnaireId()))) {
                        totalQuestionCount += answerDetails.size();

                        for (int i = 0; i < answerDetails.size(); i++) {
                            UserAnswerDetailResponseDTO detail = answerDetails.get(i);
                            if (i > 0) {
                                catAnswerData.append(";\n");
                            }
                            catAnswerData.append(String.format("%d&&%d&&%s&&%s&&%.4f&&%.4f",
                                    i + 1, // 序号
                                    detail.getQuestionSort(), // 题目序号
                                    detail.getQuestionTitle(), // 题目内容
                                    detail.getOptionId() - 1, // 选项ID
                                    detail.getReNum() != null ? detail.getReNum() : 0.0, // 能力值
                                    detail.getSeNum() != null ? detail.getSeNum() : 0.0  // 标准误
                            ));
                        }
                        // 使用CAT问卷的能力值和标准误作为最终值
                        finalReNum = userAnswer.getReNum();
                        finalSeNum = userAnswer.getSeNum();
                    }

                    if (QuestionnaireTypeEnum.QUESTIONNAIRE.getType().equals(questionnaireTypeMap.get(userAnswer.getQuestionnaireId()))) {
                        totalQuestionCount += answerDetails.size();
                        for (int i = 0; i < answerDetails.size(); i++) {
                            UserAnswerDetailResponseDTO detail = answerDetails.get(i);
                            if (i > 0) {
                                questionnaireAnswerData.append(";\n");
                            }

                            questionnaireAnswerData.append(String.format("%d&&%s&&%d",
                                    detail.getQuestionSort(), // 题目序号
                                    detail.getQuestionTitle(), // 题目内容
                                    detail.getOptionId() - 1 // 选项ID
                            ));
                        }
                    }
                }


                ExportUserAnswerDTO exportDTO = ExportUserAnswerDTO.builder()
                        .username(user.getRealName() != null ? user.getRealName() : user.getUsername())
                        .gender(getGenderString(user.getGender()))
                        .age(user.getAge() != null ? user.getAge() : 0)
                        .city(user.getCity())
                        .phone(user.getPhone())
                        .reNum(finalReNum)
                        .seNum(finalSeNum)
                        .questionCount(totalQuestionCount)
                        .catAnswerData(catAnswerData.toString())
                        .questionnaireAnswerData(questionnaireAnswerData.toString())
                        .build();

                exportData.add(exportDTO);
            }

            // 5. 使用Hutool的ExcelUtil导出Excel
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            ExcelUtil.getWriter()
                    .write(exportData, true)
                    .flush(outputStream);
            byte[] excelBytes = outputStream.toByteArray();

            String fileName = "用户答题记录_" +
                    (startTime != null ? startTime.toString() : "") +
                    (endTime != null ? "_" + endTime.toString() : "") +
                    "_" + LocalDate.now().format(DateTimeFormatter.BASIC_ISO_DATE) + ".xlsx";

            return buildDownloadResponse(excelBytes, fileName);

        } catch (Exception e) {
            log.error("导出用户答题记录失败", e);
            throw new ServiceException("导出用户答题记录失败：" + e.getMessage());
        }
    }

    /**
     * 将性别数字转换为字符串
     */
    private String getGenderString(Integer gender) {
        if (gender == null) {
            return "未知";
        }
        switch (gender) {
            case 1:
                return "男";
            case 2:
                return "女";
            default:
                return "未知";
        }
    }


    /**
     * 替换Word文档中的文本
     */
    private void replaceTextInDocument(XWPFDocument document, String placeholder, String replacement) {
        // 替换段落中的文本
        for (XWPFParagraph paragraph : document.getParagraphs()) {
            replaceTextInParagraph(paragraph, placeholder, replacement);
        }

        // 替换表格中的文本
        for (XWPFTable table : document.getTables()) {
            for (XWPFTableRow row : table.getRows()) {
                for (XWPFTableCell cell : row.getTableCells()) {
                    for (XWPFParagraph paragraph : cell.getParagraphs()) {
                        replaceTextInParagraph(paragraph, placeholder, replacement);
                    }
                }
            }
        }

        // 替换页眉页脚中的文本
        for (XWPFHeader header : document.getHeaderList()) {
            for (XWPFParagraph paragraph : header.getParagraphs()) {
                replaceTextInParagraph(paragraph, placeholder, replacement);
            }
        }

        for (XWPFFooter footer : document.getFooterList()) {
            for (XWPFParagraph paragraph : footer.getParagraphs()) {
                replaceTextInParagraph(paragraph, placeholder, replacement);
            }
        }
    }

    /**
     * 替换段落中的文本
     */
    private void replaceTextInParagraph(XWPFParagraph paragraph, String placeholder, String replacement) {
        String paragraphText = paragraph.getText();
        if (paragraphText.contains(placeholder)) {
            // 使用更高级的文本替换方法来处理跨Run的占位符
            replaceTextInRuns(paragraph, placeholder, replacement);
        }
    }

    /**
     * 处理跨Run的文本替换
     */
    private void replaceTextInRuns(XWPFParagraph paragraph, String placeholder, String replacement) {
        List<XWPFRun> runs = paragraph.getRuns();
        if (runs.isEmpty()) {
            return;
        }

        // 构建完整的段落文本
        StringBuilder fullText = new StringBuilder();
        for (XWPFRun run : runs) {
            String runText = run.getText(0);
            if (runText != null) {
                fullText.append(runText);
            }
        }

        String fullTextStr = fullText.toString();
        if (!fullTextStr.contains(placeholder)) {
            return;
        }

        // 替换文本
        String replacedText = fullTextStr.replace(placeholder, replacement);

        // 清除所有Run的文本
        for (XWPFRun run : runs) {
            run.setText("", 0);
        }

        // 将替换后的文本设置到第一个Run中
        if (!runs.isEmpty()) {
            runs.get(0).setText(replacedText, 0);
        }

        // 移除多余的Run
        for (int i = runs.size() - 1; i > 0; i--) {
            paragraph.removeRun(i);
        }
    }

    /**
     * 构建下载响应
     */
    private ResponseEntity<byte[]> buildDownloadResponse(byte[] bytes, String fileName) {
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.CONTENT_DISPOSITION, "attachment; filename=" +
                URLEncoder.encode(fileName, StandardCharsets.UTF_8));
        headers.setContentType(MediaType.APPLICATION_OCTET_STREAM);
        return ResponseEntity.ok()
                .headers(headers)
                .contentType(MediaType.APPLICATION_OCTET_STREAM)
                .body(bytes);
    }

    public List<UserAnswer> listUserAnswerByGroupId(Long userAnswerGroupId) {
        return userAnswerMapper.selectListByQuery(QueryWrapper.create().where(USER_ANSWER.USER_ANSWER_GROUP_ID.eq(userAnswerGroupId)));
    }

    /**
     * 刷新问卷题目缓存
     */
    public void refreshQuestionCache(Long questionnaireId) {
        String cacheKey = QUESTION_CACHE_KEY_PREFIX + questionnaireId;
        try {
            // 先删除旧缓存
            redisTemplate.delete(cacheKey);

            // 重新查询并缓存
            QueryWrapper questionWrapper = QueryWrapper.create()
                    .where(QUESTION.QUESTIONNAIRE_ID.eq(questionnaireId))
                    .orderBy(QUESTION.SORT.asc());
            List<Question> questions = questionMapper.selectListByQuery(questionWrapper);

            // 缓存新数据
            redisTemplate.opsForValue().set(cacheKey, questions, CACHE_EXPIRE_MINUTES, TimeUnit.MINUTES);
            log.info("已刷新问卷[{}]的题目缓存", questionnaireId);
        } catch (Exception e) {
            log.error("刷新问卷[{}]题目缓存失败: {}", questionnaireId, e.getMessage());
        }
    }

    /**
     * 删除问卷题目缓存
     */
    public void deleteQuestionCache(Long questionnaireId) {
        String cacheKey = QUESTION_CACHE_KEY_PREFIX + questionnaireId;
        try {
            redisTemplate.delete(cacheKey);
            log.info("已删除问卷[{}]的题目缓存", questionnaireId);
        } catch (Exception e) {
            log.error("删除问卷[{}]题目缓存失败: {}", questionnaireId, e.getMessage());
        }
    }

    /**
     * 批量删除问卷题目缓存
     */
    public void deleteQuestionCacheBatch(List<Long> questionnaireIds) {
        if (CollectionUtils.isEmpty(questionnaireIds)) {
            return;
        }

        try {
            List<String> cacheKeys = questionnaireIds.stream()
                    .map(id -> QUESTION_CACHE_KEY_PREFIX + id)
                    .collect(Collectors.toList());
            redisTemplate.delete(cacheKeys);
            log.info("已批量删除问卷题目缓存，问卷ID: {}", questionnaireIds);
        } catch (Exception e) {
            log.error("批量删除问卷题目缓存失败，问卷ID: {}, 错误: {}", questionnaireIds, e.getMessage());
        }
    }
} 